﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Collections;


namespace Symulacja_Routera
{
    class Program
    {
        static void Main (string[] args)
		{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////// CZĘŚĆ WCZYTUJĄCA //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			// ROUTER //
			string nazwa_sprzetu = "nazwa";
			int przeplywnosc_sprzetu = 0;
			// KOLEJKI //
			int ilosc_kolejek = 0;
			string[] nazwy_kolejek = new string[0];
			long [] rozmiary_kolejek = new long[0];
			// ROZKŁADY //
			int ilosc_rozkladow = 0;
			string[] nazwy_rozkladow = new string[0];
			double[] lambdy_rozkladow = new double[0];
			// STRUMIENIE //
			int ilosc_strumieni = 0;
			string[] nazwy_strumieni = new string[0];
			string[] kolejki_strumieni = new string[0];
			string[] rozklady_czasow_strumieni = new string[0];
			string[] rozklady_rozmiarow_strumieni = new string[0];

			string path=@"C:\Users\Piotr\Documents\AISDE\Plik.txt";
			Console.WriteLine ("########## SYMULACJA ROUTERA ##########");
			StreamReader objReader;
			Console.WriteLine ("Wprowadź pełną ścieżkę dostępu do pliku konfiguracyjnego:");
			/*while(1==1){//pytaj o poprawną ścieżkę do pliku aż do skutku!
				string path = Console.ReadLine ();
				try {
					objReader = new StreamReader (@path); // otwieramy pliku tekstowego
				} catch {
					Console.WriteLine ("Wprowadź poprawną ścieżkę:");
					continue;
				}
				break;
			}*/

            objReader = new StreamReader(@path);

			Console.WriteLine ("\n########## Proszę czekać. Symulacja trwa ##########");
            string sLine = ""; // zmienna strumieniowa (nie wiem czemu = "", ale tak było w przykładach)

            string[] tabTekst = new string[0]; // tablica do której wczytujemy linie z tekstu
            int tabTekstRozmiar = 0;
            string[] tabSlowaLini = new string[0]; // tablica, do której zapisujemy slowa z linii
            int tabSlowaLiniRozmiar = 0;

            while (sLine != null) // jeżeli wczytana linia różna od NULL
            {
                sLine = objReader.ReadLine(); // wczytujemy linię
                if (sLine != null && sLine != "" && sLine[0] != '#') // nie wiem, po co drugi raz "sLine != null" && jeżeli linia nie jest pusta 
                {
                    Array.Resize(ref tabTekst, tabTekstRozmiar + 1); // powiększamy tablicę
                    tabTekst[tabTekstRozmiar] = (sLine); // dodajemy linię do tablicy
                    tabTekstRozmiar++;
                }
            }
            objReader.Close(); // zamykamy plik tekstowy

            for (int i = 0; i < tabTekstRozmiar; i++) // wybieranie słów z linii
            {
                string[] temp = tabTekst[i].Split(new string[] { " " }, StringSplitOptions.None); // funkcja Split tworzy tablicę słów wziętych z linii
                // { " " } to warunek, który rozdziela słowa, np. jakbyś wpisał {"z"}, to słowa byłyby rozdzielane w miejscu, gdzie stoi litera z
                for (int j = 0; j < temp.Length; j++)
                {
                    if (temp[j] == "=") // wyrzucenie znakow "="
                    {
                        continue;
                    }
                    else
                    {
                        Array.Resize(ref tabSlowaLini, tabSlowaLiniRozmiar + 1); // zapisanie słów do tablicy słów
                        tabSlowaLini[tabSlowaLiniRozmiar] = temp[j];
                        tabSlowaLiniRozmiar++;
                    }
                }
            }
            // teraz wystarczy tylko wybrać sobie po indeksach odpowiednie słowa ;)
            // foreach (string sOutput in arrWord) Console.WriteLine(sOutput);

            int index = 0;
            int n = 0;

            while (index < tabSlowaLini.Length)
            {
                if (tabSlowaLini[index] == "SYSTEM")
                {
                    index += 1;
                    nazwa_sprzetu = tabSlowaLini[index];
					if(nazwa_sprzetu!="ROUTER")
						throw new ArgumentException("Wczytaj poprawny plik!");
                    index += 1;
                }
                else if (tabSlowaLini[index] == "PRZEPLYWNOSC")
                {
                    index += 1;
                    przeplywnosc_sprzetu = int.Parse(tabSlowaLini[index]);
                    index += 1;
                }
                else if (tabSlowaLini[index] == "KOLEJKI")
                {
                    index += 1;
                    ilosc_kolejek = int.Parse(tabSlowaLini[index]);
                    Array.Resize(ref nazwy_kolejek, ilosc_kolejek);
                    Array.Resize(ref rozmiary_kolejek, ilosc_kolejek);

                    for (n = 0; n < ilosc_kolejek; n++)
                    {
                        index += 2;
                        nazwy_kolejek[n] = tabSlowaLini[index];
                        index += 2;
                        rozmiary_kolejek[n] = Int64.Parse(tabSlowaLini[index]);
                    }
                    index += 1;
                }
                else if (tabSlowaLini[index] == "ROZKLADY")
                {
                    index += 1;
                    ilosc_rozkladow = int.Parse(tabSlowaLini[index]);
                    Array.Resize(ref nazwy_rozkladow, ilosc_rozkladow);
                    Array.Resize(ref lambdy_rozkladow, ilosc_rozkladow);

                    for (n = 0; n < ilosc_rozkladow; n++)
                    {
                        index += 2;
                        nazwy_rozkladow[n] = tabSlowaLini[index];
                        index += 2;
                        lambdy_rozkladow[n] = Convert.ToDouble(tabSlowaLini[index]);
                    }
                    index += 1;
                }
                else if (tabSlowaLini[index] == "STRUMIENIE")
                {
                    index += 1;
                    ilosc_strumieni = int.Parse(tabSlowaLini[index]);
                    Array.Resize(ref nazwy_strumieni, ilosc_strumieni);
                    Array.Resize(ref kolejki_strumieni, ilosc_strumieni);
                    Array.Resize(ref rozklady_czasow_strumieni, ilosc_strumieni);
                    Array.Resize(ref rozklady_rozmiarow_strumieni, ilosc_strumieni);

                    for (n = 0; n < ilosc_strumieni; n++)
                    {
                        index += 2;
                        nazwy_strumieni[n] = tabSlowaLini[index];
                        index += 2;
                        kolejki_strumieni[n] = tabSlowaLini[index];
                        index += 2;
                        rozklady_czasow_strumieni[n] = tabSlowaLini[index];
                        index += 2;
                        rozklady_rozmiarow_strumieni[n] = tabSlowaLini[index];
                    }
                    index += 1;
                }
            }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////// DALSZA CZĘŚĆ //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            double obecny_czas = 0;
            int total_time = 1000;
            bool in_service = false;

            Bufor[] bufor = new Bufor[ilosc_kolejek];
			for (n = 0; n < ilosc_kolejek; n++)
            {
                bufor[n] = new Bufor(nazwy_kolejek[n],rozmiary_kolejek[n]);
            }

            ListaNieuporzadkowana<Zdarzenie> fifo = new ListaNieuporzadkowana<Zdarzenie>(); // zarządzanie zdarzeniami (do fifo będą wstawiały zdarzenia strumienie)

            Strumien[] strumien = new Strumien[ilosc_strumieni];
            for (n = 0; n < ilosc_strumieni; n++)
            {
                int pr = 0;
                bool pr_find = false;
                double l_size = 0;
                bool l_size_find = false;
                double l_time = 0;
                bool l_time_find = false;

                for (int i = 0; i < nazwy_rozkladow.Length; i++)
                {
                    if (kolejki_strumieni[n] == nazwy_rozkladow[i])
                    {
                        pr = i;
                        pr_find = true;
                    }
                    if (rozklady_czasow_strumieni[n] == nazwy_rozkladow[i])
                    {
                        l_time = lambdy_rozkladow[i];
                        l_time_find = true;
                    }
                    if (rozklady_rozmiarow_strumieni[n] == nazwy_rozkladow[i])
                    {
                        l_size = lambdy_rozkladow[i];
                        l_size_find = true;
                    }
                    if (pr_find == true && l_size_find == true && l_time_find == true) break;
                }
                strumien[n] = new  Strumien(ref fifo, nazwy_strumieni[n], pr, l_time, l_size, n);
             
            }

            for (n = 0; n < ilosc_strumieni; n++)
            {
                strumien[n].WstawPakiet(obecny_czas); // planowanie przyszłości (losowanie pierwszych paczek)
                
            }

			//Statystyka routera
			Czasomierz timer = new Czasomierz();
			double czas_bezczynnosci=0;

			timer.start(0);//najpierw router bezczynny

			//
			while(obecny_czas<=total_time && fifo.ZwrocRozmiar()>0)
            {
				Zdarzenie e = fifo.ZwrocMin();
				fifo.UsunMin(); // to zdarzenie już się nie powtórzy
				obecny_czas=e.czas;
				Pakiet p = e.pakiet; // bierzemy paczkę z jej zdarzenia (Event)
				switch(e.typ)
                {
					case true://kiedy przychodzi nowa paczka

                        strumien[e.pakiet.priorytet].WstawPakiet(obecny_czas);

							if(bufor[p.priorytet].HaveSize(p)) // jeśli bufor ma miejsce to przyjmujemy
                            {
								p.startHandling(obecny_czas);//pomiar czasu przyjścia (potrzebny do obliczenia czasu obsługi paczki)
								bufor[p.priorytet].Insert(p, obecny_czas); // dodaj do kolejki
								bufor[p.priorytet].accept(); // informacja statystyczna
							}
                            else // jeśli więcej w buforze to nam paczka przepada
                            {
								bufor[p.priorytet].reject();
							}

							if(!in_service) // jeśli wolny
                            {
								for (int i = 0; i < ilosc_kolejek; i++) // zobacz wszystie kolejki po priorytetach
                                {
									if(!bufor[i].JestPusty()) // jeśli mamy coś w kolejce
                                    {
                                        //try
                                        //{
                                            Pakiet pp = bufor[i].WezIUsunMin(); // pobiera pierwszą paczkę z kolejki
                                            double time_service = pp.getHandlingTime(przeplywnosc_sprzetu); // pobiera czas obsługi
                                            fifo.Wstaw(new Zdarzenie(obecny_czas + time_service, false, ref pp)); // dodaj zdarzenie końca obsługi
                                            in_service = true;
                                            czas_bezczynnosci = timer.stop(obecny_czas);
                                        
                                            break;
                                        
									}
								}
							}
						break;

					case false: // jeśli paczka została już obsłużona

						double handle_time= p.endHandling(obecny_czas);//Czas obsłużenia paczki
						strumien[p.strumien_id].sredni_czas_obslugi_paczki.DodajDoSredniej(handle_time);//dodajemy do odpowiedniego strumienia kolejny składnik średniej
                        for (int i = 0; i < ilosc_kolejek; i++) // zobacz wszystie kolejki po priorytetach
                        {
                            if (!bufor[i].JestPusty()) // jeśli mamy coś w kolejce
                            {
                                //try{
                                Pakiet pp = bufor[i].WezIUsunMin(obecny_czas); // pobiera pierwszą paczkę z kolejki
	                                double time_service = pp.getHandlingTime(przeplywnosc_sprzetu); // pobiera czas obsługi
	                                fifo.Wstaw(new Zdarzenie(obecny_czas + time_service, false, ref pp)); // dodaj zdarzenie końca obsługi//dodaje zdarzenie końca obsługi
	                                in_service = true;
								//}catch{
									//Console.WriteLine("czas wyjatku: {0}", current_time);
                                	//in_service = false; // router wolny
								//}
                                break;
                            }
                            else// jeśli nic nie ma w kolejce
							{
                                in_service = false; // router wolny
								timer.start(obecny_czas);
							}
                        }
                        break;

				}

			}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////// CZĘŚĆ PODSUMOWUJĄCA I ZAPISUJĄCA //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            string[] lines = new string[0];
            int lines_size = 0;

            Array.Resize(ref lines, lines_size + 3);
            lines[lines_size] = "########## SYMULACJA ROUTERA ##########";
            lines[lines_size + 1] = "";
            lines[lines_size + 2] = "";
            lines_size += 3;

            Array.Resize(ref lines, lines_size + 4);
            lines[lines_size] = "\n\nCzas bezczynności routera: " + String.Format("{0:N2}", czas_bezczynnosci) + " a całkowity czas symulacji, to: " + String.Format("{0:N2}", obecny_czas);
            Console.WriteLine(lines[lines_size]);

            double zajetosc= (obecny_czas-czas_bezczynnosci)/obecny_czas*100;
            lines[lines_size + 1] = "Zajętość routera: " + String.Format("{0:N2}", zajetosc) + " %";
            Console.WriteLine(lines[lines_size + 1]);
            lines[lines_size + 2] = "";
            lines[lines_size + 3] = "";
            lines_size += 4;

            Array.Resize(ref lines, lines_size + 2);
            lines[lines_size] = "\n\n----Strumienie----";
            Console.WriteLine(lines[lines_size]);
            lines[lines_size + 1] = "";
            lines_size += 2;
			for (int i = 0; i < ilosc_strumieni; i++)
            {
                Array.Resize(ref lines, lines_size + 3);
                lines[lines_size] = "\nStrumień " + i + " (numer " + strumien[i].nazwa + ")";
                Console.WriteLine(lines[lines_size]);

                lines[lines_size + 1] = "_____Średni czas obsługi paczki: " + String.Format("{0:N4}",strumien[i].sredni_czas_obslugi_paczki.WezSrednia()) + " s";
                Console.WriteLine(lines[lines_size + 1]);

                lines[lines_size + 2] = "";
                lines_size += 3;
            }

            Array.Resize(ref lines, lines_size + 1);
            lines[lines_size] = "";
            lines_size += 1;

            Array.Resize(ref lines, lines_size + 2);
            lines[lines_size] = "\n\n----Bufory----";
            Console.WriteLine(lines[lines_size]);
            lines[lines_size + 1] = "";
            lines_size += 2;
			for (int i = 0; i < ilosc_kolejek; i++)
            {
                Array.Resize(ref lines, lines_size + 3);
                lines[lines_size] = "\nBufor " + i + " (numer " + bufor[i].nazwa + ")";
                Console.WriteLine(lines[lines_size]);

                lines[lines_size + 1] = bufor[i].getStatistic();
                Console.WriteLine(lines[lines_size + 1]);

                lines[lines_size + 2] = "";
                lines_size += 3;
            }

            System.IO.File.WriteAllLines(@"C:\Users\Piotr\Documents\AISDE\Router-wyniki_symulacji.txt", lines);

		Console.ReadKey();
        }
    }
}
